Skip to content

feat(domains): add Fan domain (#37)#69

Merged
Faerkeren merged 1 commit into
mainfrom
feature/fan-domain
May 26, 2026
Merged

feat(domains): add Fan domain (#37)#69
Faerkeren merged 1 commit into
mainfrom
feature/fan-domain

Conversation

@Faerkeren

Copy link
Copy Markdown
Contributor

Closes #37.

Issue validity assessment

Valid and clearly actionable. The request fits the project's design priorities (typed domain accessors, intent-specific methods, graceful degradation) and matches the structure used by existing domains such as Humidifier, Vacuum, and Cover. No ambiguity required clarification.

Fix

New Fan domain in src/haclient/domains/fan.py, registered through DomainSpec so client.fan("...") resolves automatically.

State properties

  • is_on, percentage, preset_mode, preset_modes, oscillating, direction
  • supports_set_speed, supports_oscillate, supports_direction, supports_preset_mode for capability introspection

Actions

  • on(), off(), toggle() — unconditional, like every other on/off domain
  • set_percentage(int) — validates 0–100, gated on SET_SPEED
  • set_preset_mode(str) — gated on PRESET_MODE and preset_modes, raises ValueError for modes not in the list
  • set_direction(str) — validates forward/reverse, gated on DIRECTION
  • oscillate(bool) — gated on OSCILLATE

Listener decorators

  • on_turn_on, on_turn_off, on_speed_change, on_direction_change

Graceful degradation
Optional actions check the FanEntityFeature bitmask in supported_features (SET_SPEED=1, OSCILLATE=2, DIRECTION=4, PRESET_MODE=8) before dispatching. When the feature is missing they emit a debug log and return without raising, matching the pattern already used by Vacuum.

Tests / checks run

  • pytest tests/ --cov=haclient --cov-report=term-missing --cov-fail-under=95285 passed, total coverage 97.08%, domains/fan.py at 100% (covers full-featured actions, range / direction / preset-mode validation, all degradation no-op paths, missing/malformed attribute handling, and listener decorators).
  • ruff check src tests — clean.
  • ruff format --check src tests — clean.
  • mypy src — clean (strict mode, no issues found in 37 source files).

Add a typed Fan domain accessor exposing intent-specific methods for
fan control rather than raw service calls.

State properties: is_on, percentage, preset_mode, preset_modes,
oscillating, direction, plus supports_set_speed / supports_oscillate /
supports_direction / supports_preset_mode for capability introspection.

Actions: on, off, toggle, set_percentage, set_preset_mode,
set_direction, oscillate. set_percentage validates the 0-100 range;
set_direction validates against forward/reverse; set_preset_mode
rejects modes not in preset_modes.

Listener decorators: on_turn_on, on_turn_off, on_speed_change,
on_direction_change.

Optional actions degrade safely against FanEntityFeature bits in
supported_features (SET_SPEED, OSCILLATE, DIRECTION, PRESET_MODE):
calls become a debug-logged no-op rather than raising when the
feature is not advertised, keeping user code portable across
heterogeneous fan hardware.
@Faerkeren Faerkeren merged commit e037d02 into main May 26, 2026
12 checks passed
@Faerkeren Faerkeren deleted the feature/fan-domain branch May 26, 2026 19:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add Fan domain support

1 participant